/*
 *      AnalizadorSintacticoMainFrame.java
 *
 *      Copyright 2008 Pablo Nicolas Diaz Bilotto <pablonicolas.diaz@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      This program is distributed in the hope that it will be useful,
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *      GNU General Public License for more details.
 *
 *      You should have received a copy of the GNU General Public License
 *      along with this program; if not, write to the Free Software
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *      MA 02110-1301, USA.
 */
package view;

import i386CodeGenerator.CodeGenerator;
import i386CodeGenerator.Executor;
import ilanguage.IL_SSA_Depot;
import ilanguage.iltokens.IL_BaseSSA;
import ilanguage.iltokens.IL_SSA;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringReader;
import java.util.Enumeration;
import java.util.Iterator;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JEditorPane;
import javax.swing.JFileChooser;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.ListModel;
import javax.swing.WindowConstants;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyleContext;

import lexer.MyLexer;
import numeticUItype.NumberedEditorKit;
import parser.Parser;
import symbolStorageService.ISymEntry;
import symbolStorageService.ISymTable;
import symbolStorageService.SymTable;
import errorService.IErrorReporter;



/**
* This code was edited or generated using CloudGarden's Jigloo
* SWT/Swing GUI Builder, which is free for non-commercial
* use. If Jigloo is being used commercially (ie, by a corporation,
* company or business for any purpose whatever) then you
* should purchase a license for each developer using Jigloo.
* Please visit www.cloudgarden.com for details.
* Use of Jigloo implies acceptance of these licensing terms.
* A COMMERCIAL LICENSE HAS NOT BEEN PURCHASED FOR
* THIS MACHINE, SO JIGLOO OR THIS CODE CANNOT BE USED
* LEGALLY FOR ANY CORPORATE OR COMMERCIAL PURPOSE.
*/
/**
 * The Class AnalizadorSintacticoMainFrame.
 */

public class AnalizadorSintacticoMainFrame extends javax.swing.JFrame {

    // //////////////////////////////////////////////////inner class SaveAction
    private JExecuteResult editAreaResult;
    private JScrollPane getResultExeProgram;
    /**
     * The Class CompilarAction.
     */
    
    class JExecuteResult extends JEditorPane implements PrintStream{

    	/**
    	 * 
    	 */
    	private static final long serialVersionUID = 1L;

    	public void print(String generateCodeMachine) {
    		setText(getText()+generateCodeMachine);
    		
    	}

    	public void println(Object object) {
    		print(object.toString()+"\n");
    	}

    	public void println(String string) {
    		print(string+"\n");
    		
    	}
    	
    	
    }
    
    
    class CompilarAction extends AbstractAction {

        /** The Constant serialVersionUID. */
        private static final long serialVersionUID = 1L;

        // ============================================= constructor
        /**
         * Instantiates a new compilar action.
         */
        CompilarAction() {
            super("Compilar");
            putValue(MNEMONIC_KEY, new Integer('C'));
        }

        // ========================================= actionPerformed
        /**
         * (non-Javadoc)
         *
         * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
         */
        public void actionPerformed(ActionEvent e) {

            if (!isSaved) {
                buttonSave.doClick();
            }

            if (isSaved) {
				ErrorStreamerModel modelErrores = (ErrorStreamerModel) listErrores
						.getModel();
				DefaultComboBoxModel modelTablaSimbolos = (DefaultComboBoxModel) listTablaSimbolos
						.getModel();
				DefaultComboBoxModel modelEstructuras = (DefaultComboBoxModel) listEstructuras
						.getModel();
				modelErrores.removeAllElements();
				modelTablaSimbolos.removeAllElements();
				modelEstructuras.removeAllElements();
				editAreaCode.setText("");
				highLightText(Color.black, 0, editArea.getDocument()
						.getLength());
				ISymTable symTable = new SymTable();
				StringReader input = new StringReader(editArea.getText());
				MyLexer lex = new MyLexer(input, symTable, modelErrores);
				IL_SSA_Depot stmrIL = new IL_SSA_Depot(symTable, modelErrores);
				stmrIL.clear();
				Parser myparser = new Parser(lex, stmrIL, jCheckBox1
						.isSelected());
				myparser.run();
				CodeGenerator gen;
				gen = new CodeGenerator(stmrIL, editAreaCode, symTable);
				gen.GenerateMachineCode();
				if (!stmrIL.hasErrors()) {
					try {
						AnalizadorSintacticoMainFrame.this.guardarCodigo();
						AnalizadorSintacticoMainFrame.this.guardarCodigo2exe();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
				}
				for (Enumeration<String> en = symTable.keys(); en
						.hasMoreElements();) {
					ISymEntry value;
					Object key = en.nextElement();
					value = symTable.get(key);
					modelTablaSimbolos.addElement(key + " | " + value.toGui());
				}
				for (Iterator<IL_SSA> en = stmrIL.iterator(); en.hasNext();) {
					IL_BaseSSA key = en.next();
					modelEstructuras.addElement(key);
				}
			}
        }
    }

    /**
     * The Class OpenAction.
     */
    class OpenAction extends AbstractAction {

        /** The Constant serialVersionUID. */
        private static final long serialVersionUID = 1L;

        // ============================================= constructor
        /**
         * Instantiates a new open action.
         */
        public OpenAction() {
            super("Abrir...");
            putValue(MNEMONIC_KEY, new Integer('A'));
        }

        // ========================================= actionPerformed
        /*
         * (non-Javadoc)
         *
         * @see
         * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent
         * )
         */
        public void actionPerformed(ActionEvent e) {
            int retval = fileChooser
                    .showOpenDialog(AnalizadorSintacticoMainFrame.this);
            if (retval == JFileChooser.APPROVE_OPTION) {
                File f = fileChooser.getSelectedFile();
                fileCodFuente = f.getAbsolutePath();
                try {
                    FileReader reader = new FileReader(f);
                    editArea.read(reader, ""); // Use TextComponent read
                    isSaved = true;
                } catch (IOException ioex) {
                    System.out.println(e);
                    System.exit(1);
                }
            }
        }
    }

    // ////////////////////////////////////////////////// inner class SaveAction
    /**
     * The Class SaveAction.
     */
    class SaveAction extends AbstractAction {

        /** The Constant serialVersionUID. */
        private static final long serialVersionUID = 1L;

        // ============================================= constructor
        /**
         * Instantiates a new save action.
         */
        SaveAction() {
            super("Guardar...");
            putValue(MNEMONIC_KEY, new Integer('G'));
        }

        // ====================================== === actionPerformed
        /**
         * (non-Javadoc)
         *
         * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent
         *      )
         */
        public void actionPerformed(ActionEvent e) {
            if (editArea.getText().length() > 0) {
                File f = null;
                int retval = fileChooser
                        .showSaveDialog(AnalizadorSintacticoMainFrame.this);
                if (retval == JFileChooser.APPROVE_OPTION) {
                    f = fileChooser.getSelectedFile();
                    fileCodFuente = f.getAbsolutePath();
                }
                if (f != null) {
                    try {
                        FileWriter writer = new FileWriter(f);
                        editArea.write(writer); // Use TextComponent write
                        isSaved = true;
                    } catch (IOException ioex) {
                        JOptionPane.showMessageDialog(
                                AnalizadorSintacticoMainFrame.this, ioex);
                        System.exit(1);
                    }
                }
            }
        }
    }

    /** The edit area code. */
    private JEditorPaneCode editAreaCode;

    /** The generate code scroll panel. */
    private JScrollPane generateCodeScrollPanel;

    /** The Constant serialVersionUID. */
    private static final long serialVersionUID = 1L;

    /** The file chooser. */
    private JFileChooser fileChooser;

    /** The menu principal. */
    private JMenuBar menuPrincipal;

    /** The save action. */
    private SaveAction saveAction;
    private JCheckBox jCheckBox1;

    /** The open action. */
    private OpenAction openAction;

    /** The list tabla simbolos. */
    private JList listTablaSimbolos;

    /** The scrolling tabla simbolos. */
    private JScrollPane scrollingTablaSimbolos;

    /** The list errores. */
    private JList listErrores;

    /** The panel tabla simbolos. */
    private JPanel panelTablaSimbolos;

    /** The button compilar. */
    private JButton buttonCompilar;

    /** The button save. */
    private JButton buttonSave;

    /** The button open. */
    private JButton buttonOpen;

    /** The edit area. */
    private JEditorPane editArea;

    /** The scrolling text. */
    private JScrollPane scrollingText;

    /** The panel texto. */
    private JPanel panelTexto;

    /** The scrolling errores. */
    private JScrollPane scrollingErrores;

    /** The scrolling estructuras. */
    private JScrollPane scrollingEstructuras;

    /** The panel errores. */
    private JPanel panelErrores;

    /** The list estructuras. */
    private JList listEstructuras;

    /** The panel estructuras. */
    private JPanel panelEstructuras;

    /** The compilar action. */
    private CompilarAction compilarAction;

    /** The exit action. */
    private ExitAction exitAction;

    /** The file cod fuente. */
    public static String fileCodFuente = null;

    /** The is saved. */
    private boolean isSaved = true;

    /**
     * Instantiates a new analizador sintactico main frame.
     */
    public AnalizadorSintacticoMainFrame() {
        super();
        saveAction= new SaveAction();
        openAction = new OpenAction();
        compilarAction = new CompilarAction();
        exitAction = new ExitAction();
        initGUI();
        this.setLocationRelativeTo(null);
        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent evt) {
                rootWindowClosing(evt);
            }
        });
        final JTabbedPane tabbedPane = new JTabbedPane();
        tabbedPane.setBounds(3, 360, 730, 300);
        getContentPane().add(tabbedPane);
        {
            panelErrores = new JPanel();
            panelErrores.setLayout(new BorderLayout());
            tabbedPane.addTab("Errors & Warnings", null, panelErrores, null);
            {
                scrollingErrores = new JScrollPane();
                panelErrores.add(scrollingErrores);
                {
                    listErrores = new JList();
                    scrollingErrores.setViewportView(listErrores);
                    listErrores.setModel(new ErrorStreamerModel());
                }
            }
        }
        {
            panelEstructuras = new JPanel();
            panelEstructuras.setLayout(new BorderLayout());
            tabbedPane.addTab("Tercetos", null, panelEstructuras, null);
            {
                scrollingEstructuras = new JScrollPane();
                panelEstructuras.add(scrollingEstructuras);
                {
                    listEstructuras = new JList();
                    scrollingEstructuras.setViewportView(listEstructuras);
                    listEstructuras.setModel(new DefaultComboBoxModel());
                }
            }
        }
        panelTablaSimbolos = new JPanel();
        panelTablaSimbolos.setLayout(new BorderLayout());
        tabbedPane.addTab("Tabla de Simbolos", null, panelTablaSimbolos, null);
        scrollingTablaSimbolos = new JScrollPane();
        panelTablaSimbolos.add(scrollingTablaSimbolos);
        listTablaSimbolos = new JList();
        scrollingTablaSimbolos.setViewportView(listTablaSimbolos);
        ListModel listTablaSimbolosModel = new DefaultComboBoxModel();
        listTablaSimbolos.setModel(listTablaSimbolosModel);

        final JPanel assemblerPanel = new JPanel();
        assemblerPanel.setLayout(new BorderLayout());
        tabbedPane.addTab("Codigo Assembler", null, assemblerPanel, null);

        generateCodeScrollPanel = new JScrollPane();
        assemblerPanel.add(generateCodeScrollPanel);

        editAreaCode = new JEditorPaneCode();
        generateCodeScrollPanel.setViewportView(editAreaCode);

        final JPanel ExecuteprogramPanel = new JPanel();
        ExecuteprogramPanel.setLayout(new BorderLayout());
        tabbedPane.addTab("Salida del ejecutable(solo en Windows)", null, ExecuteprogramPanel, null);

        getResultExeProgram = new JScrollPane();
        ExecuteprogramPanel.add(getResultExeProgram);

        editAreaResult = new JExecuteResult();
        editAreaResult.setForeground(new Color(255, 255, 255));
        editAreaResult.setFont(new Font("Lucida Console", Font.PLAIN, 14));
        editAreaResult.setBackground(Color.BLACK);
        getResultExeProgram.setViewportView(editAreaResult);

        final JPanel panel_1 = new JPanel();
        ExecuteprogramPanel.add(panel_1, BorderLayout.SOUTH);

        final JButton ejecutarexeButton = new JButton();
        ejecutarexeButton.addActionListener(new ActionListener() {
        	public void actionPerformed(final ActionEvent arg0) {
        		if (isSaved)
        			Executor.Execute(fileCodFuente, editAreaResult);
        	}
        });
        panel_1.add(ejecutarexeButton);
        ejecutarexeButton.setText("Ejecutar .exe");
    }

    /**
     * @throws IOException
     */
    public void guardarCodigo() throws IOException {
    	FileWriter fr = null;
	      fr = new FileWriter(fileCodFuente+".asm");
	      fr.write(editAreaCode.getText());
	      fr.close();
	}
    public void guardarCodigo2exe() throws IOException {
    	FileWriter fr = null;
	      fr = new FileWriter(System.getProperty("user.dir") + "\\TASM\\codigo.asm");
	      fr.write(editAreaCode.getText());
	      fr.close();
	}
	/**
     * Edits the area key pressed.
     *
     * @param evt the evt
     */
    private void editAreaKeyPressed(KeyEvent evt) {
        String teclasOmitidas = "" + KeyEvent.VK_DOWN + KeyEvent.VK_UP
                + KeyEvent.VK_LEFT + KeyEvent.VK_RIGHT;
        if (!teclasOmitidas.contains("" + evt.getKeyCode())) {
            isSaved = false;
        }

    }

    /**
     * Gets the file cod fuente.
     *
     * @return the file cod fuente
     */
    public String getFileCodFuente() {
        return fileCodFuente;
    }

    /**
     * High light text.
     *
     * @param color the color
     * @param lineNumber the line number
     */
    public void highLightText(Color color, int lineNumber) {
        try {
            String codigo = editArea.getDocument().getText(0,
                    editArea.getDocument().getLength());
            int currentLine = 0;
            int pos = 0;
            while ((currentLine < lineNumber) && (pos != -1)) {
                pos = codigo.indexOf('\n', pos + 1);
                if (pos != -1) {
                    currentLine++;
                }
            }
            highLightText(color, pos, 1);
        } catch (BadLocationException e) {
        }
    }

    /**
     * High light text.
     *
     * @param color the color
     * @param offset the offset
     * @param length the length
     */
    public void highLightText(Color color, int offset, int length) {
        StyleContext sc = new StyleContext();
        DefaultStyledDocument doc = (DefaultStyledDocument) editArea
                .getDocument();
        // Create and add the style
        Style heading2Style = sc.addStyle("Heading2", null);
        heading2Style.addAttribute(StyleConstants.Foreground, color);
        heading2Style.addAttribute(StyleConstants.LeftIndent, new Float(25.0f));
        doc.setParagraphAttributes(offset, length, heading2Style, false);
    }

    /**
     * Inits the gui.
     */
    private void initGUI() {
        try {
            setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
            getContentPane().setLayout(null);
            this.setTitle("SUPER COMPILADOR");
            this.setResizable(false);
            {
                fileChooser = new JFileChooser();
                fileChooser.setCurrentDirectory(new File(".\\"));
                menuPrincipal = new JMenuBar();
                final JMenu menu = new JMenu("Archivo");
                JMenu fileMenu = menuPrincipal.add(menu);
                fileMenu.setMnemonic('A');
                fileMenu.add(openAction); // Note use of actions, not text.
                fileMenu.add(compilarAction);
                final JMenuItem newItemMenuItem = new JMenuItem();
                newItemMenuItem.addActionListener(saveAction);
                newItemMenuItem.setText("Guardar");
                menu.add(newItemMenuItem);
                fileMenu.addSeparator();
                fileMenu.add(exitAction);
                setJMenuBar(menuPrincipal);
                menuPrincipal.setPreferredSize(new java.awt.Dimension(765, 17));
            }
            {
                panelTexto = new JPanel();
                getContentPane().add(panelTexto);
                panelTexto.setLayout(null);
                panelTexto.setBounds(7, 7, 730, 345);
                panelTexto.setBorder(BorderFactory
                        .createTitledBorder("Codigo Fuente"));
                {
                    scrollingText = new JScrollPane();
                    panelTexto.add(scrollingText);
                    scrollingText.setBounds(14, 21, 700, 280);
                    {
                        editArea = new JEditorPane();
                        editArea.setEditorKit(new NumberedEditorKit());
                        scrollingText.setViewportView(editArea);
                        editArea.setSize(750, 750);
                        editArea.addKeyListener(new KeyAdapter() {
                            public void keyPressed(KeyEvent evt) {
                                editAreaKeyPressed(evt);
                            }
                        });
                    }
                }
                {
                    buttonOpen = new JButton();
                    buttonOpen.setToolTipText("Abrir un Archivo");
                    panelTexto.add(buttonOpen);
                    buttonOpen.setText("Abrir");
                    buttonOpen.setBounds(414, 307, 98, 28);
                    buttonOpen.addActionListener(openAction);
                }
                {
                    buttonSave = new JButton();
                    buttonSave.addActionListener(saveAction);
                    buttonSave.setToolTipText("Guardar");
                    panelTexto.add(buttonSave);
                    buttonSave.setText("Guardar");
                    buttonSave.setBounds(518, 307, 98, 28);
                }
                {
                    buttonCompilar = new JButton();
                    buttonCompilar.setToolTipText("Compilar archivo");
                    panelTexto.add(buttonCompilar);
                    buttonCompilar.setText("Compilar");
                    buttonCompilar.setBounds(622, 307, 98, 28);
                    buttonCompilar.addActionListener(compilarAction);
                }
                {
                	jCheckBox1 = new JCheckBox();
                	panelTexto.add(jCheckBox1);
                	jCheckBox1.setText("Debug Parser?");
                	jCheckBox1.setBounds(286, 311, 117, 16);
                }
            }
            pack();
            this.setSize(744, 706);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Root window closing.
     *
     * @param evt the evt
     */
    private void rootWindowClosing(WindowEvent evt) {
    }

    /**
     * Sets the file cod fuente.
     *
     * @param fileCodFuente the new file cod fuente
     */
    public void setFileCodFuente(String fileCodFuente) {
        this.fileCodFuente = fileCodFuente;
    }
}

class ErrorStreamerModel extends DefaultComboBoxModel implements IErrorReporter {
    private static final long serialVersionUID = 1L;

    public void reportError(int LineNumber, String Message) {
        super.addElement("ERROR Linea: " + LineNumber + " | " + Message);
    }

    public void reportWarning(int LineNumber, String Message) {
        super.addElement("WARNING Linea: " + LineNumber + " | " + Message);
    }
}



// /////////////////////////////////////////////////// inner class ExitAction
class ExitAction extends AbstractAction {
    private static final long serialVersionUID = 1L;

    // ============================================= constructor
    public ExitAction() {
        super("Salir");
        putValue(MNEMONIC_KEY, new Integer('X'));
    }

    // ========================================= actionPerformed
    public void actionPerformed(ActionEvent e) {
        System.exit(0);
    }
}

class JEditorPaneCode extends JEditorPane implements PrintStream {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    @Override
    public void print(String generateCodeMachine) {
        super.setText(super.getText() + generateCodeMachine);

    }

    public void println(Object object) {
        println(object.toString());

    }

    public void println(String string) {
        super.setText(super.getText() + string + "\n");
    }

}
